home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
AX25CMD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-05
|
19KB
|
879 lines
/*
** FILE: ax25cmd.c
**
** AX.25 command handler.
**
** 09/24/90 Bob Applegate, wa2zzx
** Added BCTEXT, BC, and BCINTERVAL commands for broadcasting an id
** string using UI frames.
*/
#include <stdio.h>
#include <time.h>
#include "global.h"
#include "config.h"
#ifdef AX25
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "ax25.h"
#include "cmdparse.h"
#include "socket.h"
#include "session.h"
#include "tty.h"
#ifdef NETROM
#include "nr4.h"
#endif
#include "commands.h"
#include "asy.h"
#ifdef SCC
#include "scc.h"
#endif
#ifdef VANESSA
#include "vanessa.h"
#endif
#define next_seq(n) (((n) + 1) & 7)
#define SECSPERDAY 86400L
/* Defaults for IDing... */
static char Axbctext[256];
int32 Axholdtime = AXROUTEHOLDTIME;
char *Ax25states[] = {
"",
"Disconnected",
"Listen",
"Conn pending",
"Disc pending",
"Connected",
"Time wait",
};
char *Ax25reasons[] = {
"Normal",
"Reset",
"Timeout",
"Network",
};
static void near
axifout(int(*func)())
{
struct iface *ifp;
int(*foo) __ARGS((struct iface *ifp));
foo = func;
for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
if(ifp->output == ax_output) {
(*foo)(ifp);
}
}
}
/* Verify that axp points to a valid ax25 control block */
static int near
ax25val(struct ax25_cb *axp,int(*func)(),char *s)
{
struct ax25_cb *axp1;
int all = stricmp(s,"all"), (*foo) __ARGS((struct ax25_cb *axp1));
foo = func;
if(axp != NULLAX25) {
for(axp1 = Ax25_cb; axp1 != NULLAX25; axp1 = axp1->next) {
if(axp1->state != LISTEN && (!all || (all && (axp1 == axp)))) {
/*
if(foo == st_ax25) {
tprintf("&AXCB %lx &Peer %lx\n",ptol(axp1),ptol(axp1->peer));
}
*/
if(axp1->dama && foo == kick_ax25) {
set_timer(&axp1->t1,T1init * 2000L);
}
(*foo)(axp1);
if(all) {
return 0;
}
}
}
}
if(all) {
tputs(Notval);
return -1;
}
return 0;
}
/* This is the low-level broadcast function. */
static int
ax_bc(struct iface *ifp)
{
/* prepare the header */
int i = strlen(Axbctext);
struct mbuf *hbp = alloc_mbuf(i);
hbp->cnt = i;
memcpy(hbp->data,Axbctext,i);
return (*ifp->output)(ifp,Ax25multi[2],ifp->hwaddr,PID_NO_L3,hbp); /* send it */
}
/* This function is called to send the current broadcast message */
static int
dobc(int argc,char **argv,void *p)
{
if(argc < 2) {
axifout(ax_bc);
} else {
struct iface *ifp;
while(--argc > 0) {
if((ifp = cmp_if(*++argv)) != NULLIF)
ax_bc(ifp);
}
}
return 0;
}
/* View/Change the message we broadcast. */
static int
dobctext(int argc,char **argv,void *p)
{
if (argc < 2) {
if(Axbctext[0] != '\0')
tprintf("%s\n",Axbctext);
} else {
Axbctext[0] = '\0';
while(--argc > 0) {
strcat(Axbctext,*++argv);
if(strlen(Axbctext) > 220)
break;
strcat(Axbctext," ");
}
if(strlen(Axbctext) > 2) {
strcat(Axbctext,AX_EOL);
strcat(Axbctext,"\0");
} else
Axbctext[0] = '\0';
}
return 0;
}
static int
dobud(int argc,char **argv,void *p)
{
char tmp[AXBUF];
if(!(setcall(tmp,argv[1]))) {
is_bud(tmp,1);
return 0;
}
return -1;
}
/* Force a retransmission */
int
kick_ax25(struct ax25_cb *axp)
{
return ax25val(axp,t1_timeout,0);
}
static int
doaxclose(int argc,char **argv,void *p)
{
return ax25val((struct ax25_cb *)shtop(argv[1]),disc_ax25,argv[1]);
}
static int
doaxreset(int argc,char **argv,void *p)
{
return ax25val((struct ax25_cb *)shtop(argv[1]),reset_ax25,argv[1]);
}
static int
axheard(struct iface *ifp)
{
int j;
struct lq *lp;
char *cp, tmp[AXBUF];
if(ifp->hwaddr == NULLCHAR) {
return 0;
}
for(lp = ifp->lq, j = 0; j < ifp->Hcurrent; lp++, j++) {
cp = ctime(&lp->time);
if(j == 0) {
tprintf("Iface: %s\n%-12s%-28s%-11s%s\n",
ifp->name,"Call","heard","Call","heard");
}
if(!(j % 2))
cp[24] = '\0';
tprintf("%-10s%26s",pax25(tmp,lp->addr),cp);
if(!(j % 2))
tputs(" ");
}
if(j && (j % 2))
tputs("\n");
return 0;
}
int
doaxheard(int argc,char **argv,void *p)
{
tprintf("System time: %s",ctime(&currtime));
if(argc < 2) {
axifout(axheard);
} else {
struct iface *ifp;
while(--argc > 0) {
if((ifp = cmp_if(*++argv)) != NULLIF)
axheard(ifp);
}
}
return 0;
}
static int
doaxflush(int argc,char **argv,void *p)
{
axifout(axflush);
return 0;
}
static char * near
pathtostr(struct ax25_cb *cp)
{
char *ap, *p;
static char buf[128];
if (!cp->pathlen) return "*";
p = buf;
ap = cp->path + AXALEN;
if (!addreq(ap,cp->iface->hwaddr)) {
pax25(p, ap);
while (*p) p++;
*p++ = '-';
*p++ = '>';
}
pax25(p, cp->path);
while (*p) p++;
while (!(ap[ALEN] & E)) {
ap += AXALEN;
*p++ = ',';
pax25(p, ap);
while (*p) p++;
if (ap[ALEN] & REPEATED) *p++ = '*';
}
*p = '\0';
return buf;
}
/* Dump one control block */
int
st_ax25(struct ax25_cb *cp)
{
int i;
tprintf("Path: %s%s\nIface: %s State: %s\n",
pathtostr(cp),
cp->dama ? " [DAMA]" : "",
cp->iface ? cp->iface->name : "???",
Ax25states[cp->state]);
tprintf("Closed: %-5sPolling: %-5sREJsent: %-5sRNRsent: %-6sRNRrecv: ",
cp->closed ? "Yes" : "No",
cp->polling ? "Yes" : "No",
cp->rejsent ? "Yes" : "No",
cp->rnrsent ? "Yes" : "No");
if (cp->remotebusy) {
tprintf("%ld sec", currtime - cp->remotebusy);
} else {
tputs("No");
}
tprintf("\nCWind: %-6dRetry: %-7dUnack: %-7dSRT: %2ld sec MDev: %2ld sec\nT1: ",
cp->cwind,
cp->retries,
cp->unack,
cp->srt / 1000L,
cp->mdev / 1000L);
if (run_timer(&cp->t1)) {
tprintf("%ld",read_timer(&cp->t1) / 1000L);
} else {
tputs("-");
}
tprintf("/%ld sec T2: ",dur_timer(&cp->t1) / 1000L);
if (run_timer(&cp->t2)) {
tprintf("%ld",read_timer(&cp->t2) / 1000L);
} else {
tputs("-");
}
tprintf("/%ld sec T3: ",dur_timer(&cp->t2) / 1000L);
if (run_timer(&cp->t3)) {
tprintf("%ld",read_timer(&cp->t3) / 1000L);
} else {
tputs("-");
}
tprintf("/%ld sec T4: ",dur_timer(&cp->t3) / 1000L);
if (run_timer(&cp->t4)) {
tprintf("%ld",read_timer(&cp->t4) / 1000L);
} else {
tputs("-");
}
tprintf("/%ld sec T5: ",dur_timer(&cp->t4) / 1000L);
if (run_timer(&cp->t5)) {
tprintf("%ld",read_timer(&cp->t5) / 1000L);
} else {
tputs("-");
}
tprintf("/%ld sec\n",dur_timer(&cp->t5) / 1000L);
if(cp->rxq) {
tprintf("Rcv queue: %d\n", len_p(cp->rxq));
}
if (cp->reseq[0].bp || cp->reseq[1].bp ||
cp->reseq[2].bp || cp->reseq[3].bp ||
cp->reseq[4].bp || cp->reseq[5].bp ||
cp->reseq[6].bp || cp->reseq[7].bp) {
tputs("Reassembly queue:\n");
for (i = next_seq(cp->vr); i != cp->vr; i = next_seq(i)) {
if (cp->reseq[i].bp) {
tprintf(" Seq %3d: %3d bytes\n",
i,len_p(cp->reseq[i].bp));
}
}
}
if(cp->txq) {
tprintf("Snd queue: %d\n", len_p(cp->txq));
}
if (cp->rxasm) {
struct mbuf *bp;
tputs("Resend queue:\n");
for (i = 0, bp = cp->rxasm; bp; i++, bp = bp->anext) {
tprintf(" Seq %3d: %3d bytes\n",
(cp->vs - cp->unack + i) & 7,len_p(bp));
}
}
return 0;
}
/* Display AX.25 link level control blocks */
static int
doaxstat(int argc,char **argv,void *p)
{
struct ax25_cb *axp;
char tmp[AXBUF];
if(argc < 2){
tputs("&AXCB Rcv-Q Snd-Q Local Remote Iface State\n");
for(axp = Ax25_cb; axp != NULLAX25; axp = axp->next){
if(axp->state == LISTEN) {
tprintf("%lx%55s\n",ptol(axp),"Listen (S)");
continue;
}
tprintf("%lx %6d%6d %-10s",
ptol(axp),len_p(axp->rxq),len_p(axp->txq),pax25(tmp,axp->path + AXALEN));
tprintf("%-10s%-10s%s\n",
pax25(tmp,axp->path),
axp->iface ? axp->iface->name : "???",
Ax25states[axp->state]);
}
return 0;
}
return ax25val((struct ax25_cb *)shtop(argv[1]),st_ax25,argv[1]);
}
/* Display or change our AX.25 address */
static int
domycall(int argc,char **argv,void *p)
{
char tmp[AXBUF];
if(argc < 2){
tprintf("%s\n",pax25(tmp,Mycall));
} else {
if(setcall(Mycall,argv[1]) == -1)
return -1;
}
return 0;
}
/* Control AX.25 digipeating */
static int
dodigipeat(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->digipeat,"Digipeat",--argc,++argv,0,2);
return -1;
}
static int
dot1(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->t1init,"T1init",--argc,++argv,3,30);
return -1;
}
static int
dot2(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->t2init,"T2init",--argc,++argv,0,ifp->flags->t1init/2);
return -1;
}
static int
dot3(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->t3init,"T3init",--argc,++argv,0,3600);
return -1;
}
static int
dot4(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->t4init,"T4init",--argc,++argv,ifp->flags->t1init*2,ifp->flags->t1init*20);
return -1;
}
static int
dot5(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->t5init,"T5init",--argc,++argv,0,ifp->flags->t2init-1);
return -1;
}
/* Set retry limit count */
static int
doretries(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->retries,"Retries",--argc,++argv,0,50);
return -1;
}
/* Force a retransmission */
static int
doaxkick(int argc,char **argv,void *p)
{
return ax25val((struct ax25_cb *)shtop(argv[1]),kick_ax25,argv[1]);
}
/* Set maximum number of frames that will be allowed in flight */
static int
domaxframe(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->maxframe,"Maxframe",--argc,++argv,1,7);
return -1;
}
static int
domaxheard(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF) {
if(argc < 3) {
int16 i = ifp->Hmax;
setintrc(&i,"Maxheard",--argc,++argv,2,40);
ifp->Hmax = i;
} else {
return(maxheard(ifp,atoi(argv[2])));
}
}
return -1;
}
static int
dot3disc(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->t3disc,"T3disc",--argc,++argv,0,1);
return -1;
}
/* Set maximum length of I-frame data field */
static int
dopaclen(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->paclen,"Paclen",--argc,++argv,1,2048);
return -1;
}
/* Set size of I-frame above which polls will be sent after a timeout */
static int
dopthresh(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->pthresh,"Pthresh",--argc,++argv,0,ifp->flags->paclen);
return -1;
}
/* Set high water mark on receive queue that triggers RNR */
static int
doaxwindow(int argc,char **argv,void *p)
{
struct iface *ifp;
if((ifp = cmp_if(argv[1])) != NULLIF)
return setintrc(&ifp->flags->axwindow,"Axwindow",
--argc,++argv,ifp->flags->paclen/2,ifp->flags->paclen*8);
return -1;
}
/* End of ax25 subcommands */
/* Initiate interactive AX.25 connect to remote station */
int
doconnect(int argc,char **argv,void *p)
{
char *ap, tmp[AXBUF], path[10*AXALEN];
struct session *sp;
struct iface *ifp;
struct sockaddr_ax fsocket;
struct ax25_cb axp;
argc--;
argv++;
if((ifp = if_lookup(*argv)) != NULLIF) {
if(ifp->output != ax_output) {
tprintf(Badax,*argv);
return -1;
}
argc--;
argv++;
}
for (ap = path; argc > 0; argc--, argv++) {
if (!strncmp("via", *argv, strlen(*argv))) continue;
if (ap >= path + sizeof(path)) {
tputs("Max 8 digis\n");
return -1;
}
if (setcall(ap, *argv)) {
tprintf(Invcall, *argv);
return -1;
}
ap[ALEN] &= ~E;
if (ap == path) {
ap += AXALEN;
addrcp(ap,Mycall);
ap[ALEN] &= ~E;
}
ap += AXALEN;
}
if (ap < path + 2 * AXALEN) {
tputs("Missing call\n");
return -1;
}
ap[-1] |= E;
memset(&axp,0,sizeof(struct ax25_cb));
build_path(&axp,ifp,path,0);
if(!axp.iface) {
tputs("No specified iface\n");
return -1;
}
addrcp(axp.path + AXALEN,axp.iface->hwaddr);
pax25(tmp,axp.path);
if(callreq(axp.path)) {
tprintf(Invcall,tmp);
return -1;
}
axroute_add(&axp,0);
/* Allocate a session descriptor */
if((sp = newsession(tmp,AX25TNC,SPLIT | SWAP)) == NULLSESSION){
tputs(Nosess);
return -1;
}
if((sp->s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
tputs(Nosocket);
goto quit;
}
fsocket.sax_family = AF_AX25;
memcpy(fsocket.ax25_addr,axp.path,AXALEN);
memcpy(fsocket.iface,axp.iface->name,ILEN);
if(!(tel_connect(sp,(char *)&fsocket,SOCKSIZE)))
return 0;
quit:
keywait(NULLCHAR,1);
freesession(sp);
return -1;
}
static int
dorouteadd(int argc,char **argv,void *p)
{
char *ap;
int perm;
struct ax25_cb cb;
argc--;
argv++;
if((perm = !strcmp(*argv, "permanent")) != 0) {
argc--;
argv++;
}
if((cb.iface = cmp_if(*argv)) == NULLIF)
return -1;
argc--;
argv++;
if (!strcmp(*argv,"default")) {
axroute_default_ifp = cb.iface;
return 0;
}
for (ap = cb.path; argc > 0; argc--, argv++) {
if (!strncmp("via", *argv, strlen(*argv)))
continue;
if (ap >= cb.path + sizeof(cb.path)) {
tputs("Max 8 digis\n");
return -1;
}
if (setcall(ap, *argv)) {
tprintf(Invcall, *argv);
return -1;
}
if (ap == cb.path) {
ap += AXALEN;
addrcp(ap,cb.iface->hwaddr);
}
ap += AXALEN;
}
if (ap < cb.path + 2 * AXALEN) {
tputs("Missing call\n");
return -1;
}
ap[-1] |= E;
cb.pathlen = (int)(ap - cb.path);
axroute_add(&cb, perm);
return 0;
}
#include "smtp.h" /* for 'Months' */
static void near
doroutelistentry(struct axroute_tab *rp)
{
struct axroute_tab *rp_stack[20];
struct iface *ifp;
struct tm *tm = gmtime(&rp->time);
int i, n, perm = rp->perm;
char *buf = mxallocw(10*AXBUF), *cp = buf;
pax25(cp,(char *)&rp->call);
for (n = 0; rp; rp = rp->digi) {
rp_stack[++n] = rp;
ifp = rp->ifp;
}
for (i = n; i > 1; i--) {
strcat(cp, i == n ? " via " : ",");
while (*cp) cp++;
pax25(cp,(char *)&rp_stack[i]->call);
}
tprintf("%2d-%.3s %02d:%02d %-9s %c %s\n",
tm->tm_mday,
Months[tm->tm_mon],
tm->tm_hour,
tm->tm_min,
ifp ? ifp->name : "???",
perm ? '*' : ' ',
buf);
xfree(buf);
}
int
doroutelist(int argc,char **argv,void *p)
{
struct axroute_tab *rp;
tputs("Date GMT Interface P Path\n");
if (argc < 2) {
for (rp = Axroute_tab; rp; rp = rp->next) {
doroutelistentry(rp);
}
} else {
int i;
struct ax25_addr call;
char tmp[AXBUF];
for(i = 1; i < argc; i++) {
if(setcall((char *)&call,argv[i]) || (rp = axroute_tabptr(&call,0)) == 0) {
tprintf("*** no route to %s\n",pax25(tmp,(char *)&call));
} else {
doroutelistentry(rp);
}
}
}
return 0;
}
static int
doroutehold(int argc,char **argv,void *p)
{
int16 holdtime = (int16)(Axholdtime / SECSPERDAY);
if(setintrc(&holdtime,"Holdtime (days)",argc,argv,1,120) == 0) {
Axholdtime = (int32)(holdtime * SECSPERDAY);
return 0;
}
return -1;
}
static int
doroutestat(int argc,char **argv,void *p)
{
struct ifptable_t {
struct iface *ifp;
int count;
} ;
int dev, total;
struct axroute_tab *rp, *dp;
struct iface *ifp;
struct ifptable_t ifptable[ASY_MAX
#ifdef SCC
+ MAXSCC
#endif
#ifdef VANESSA
+ VAN_MAX
#endif
#ifdef AXIP
+ NAX25
#endif
];
memset(ifptable,0,sizeof(ifptable));
for (ifp = Ifaces; ifp; ifp = ifp->next)
if (ifp->output == ax_output)
ifptable[ifp->niface].ifp = ifp;
for (rp = Axroute_tab; rp; rp = rp->next) {
for (dp = rp; dp->digi; dp = dp->digi) ;
if (dp->ifp)
ifptable[dp->ifp->niface].count++;
}
tputs("Interface Count\n");
for (total = 0, dev = 0; dev < Niface; dev++) {
if(ifptable[dev].count /*|| ifptable[dev].ifp == axroute_default_ifp*/) {
tprintf("%c %-7s %5d\n",
ifptable[dev].ifp == axroute_default_ifp ? '*' : ' ',
ifptable[dev].ifp->name,
ifptable[dev].count);
total += ifptable[dev].count;
}
}
tprintf(" total %5d\n", total);
return 0;
}
/* Display and modify AX.25 routing table */
static int
doaxroute(int argc,char **argv,void *p)
{
struct cmds Routecmds[] = {
{"add", dorouteadd, 0, 3, "ax25 route add [permanent] <iface> <path>"},
{"hold", doroutehold, 0, 0, NULLCHAR},
{"list", doroutelist, 0, 0, NULLCHAR},
{"stat", doroutestat, 0, 0, NULLCHAR},
{NULLCHAR, NULLFP, 0, 0, NULLCHAR}
};
return subcmd(Routecmds,argc,argv,p);
}
/* Multiplexer for top-level ax25 command */
int
doax25(int argc,char **argv,void *p)
{
struct cmds Axcmds[] = {
{"bc", dobc, 0, 0, NULLCHAR},
{"bctext", dobctext, 0, 0, NULLCHAR},
{"bud", dobud, 0, 2, "ax25 bud <call>"},
{"close", doaxclose, 0, 2, "ax25 close <axcb>"},
{"digipeat", dodigipeat, 0, 2, "ax25 digipeat <iface>"},
{"flush", doaxflush, 0, 0, NULLCHAR},
{"heard", doaxheard, 0, 0, NULLCHAR},
{"kick", doaxkick, 0, 2, "ax25 kick <axcb>"},
{"maxframe", domaxframe, 0, 2, "ax25 maxframe <iface>"},
{"maxheard", domaxheard, 0, 2, "ax25 maxheard <iface>"},
{"mycall", domycall, 0, 0, NULLCHAR},
{"paclen", dopaclen, 0, 2, "ax25 paclen <iface>"},
{"pthresh", dopthresh, 0, 0, NULLCHAR},
{"reset", doaxreset, 0, 2, "ax25 reset <axcb>"},
{"retry", doretries, 0, 2, "ax25 retry <iface>"},
{"route", doaxroute, 0, 0, NULLCHAR},
{"status", doaxstat, 0, 0, NULLCHAR},
{"t1", dot1, 0, 2, "ax25 t1 <iface>"},
{"t2", dot2, 0, 2, "ax25 t2 <iface>"},
{"t3", dot3, 0, 2, "ax25 t3 <iface>"},
{"t3disc", dot3disc, 0, 2, "ax25 t3disc <iface>"},
{"t4", dot4, 0, 2, "ax25 t4 <iface>"},
{"t5", dot5, 0, 2, "ax25 t5 <iface>"},
{"window", doaxwindow, 0, 2, "ax25 window <iface>"},
{NULLCHAR, NULLFP, 0, 0, NULLCHAR}
};
return subcmd(Axcmds,argc,argv,p);
}
#endif